package com.server.config.security;

import com.server.service.IAdminService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * @ClassName: JwtAuthenticationTokenFilter
 * @Description: JWT登录授权过滤器
 * @Author: SongHL
 * @Date: 2025/9/13
 */
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Value("${jwt.tokenHeader}")
    private String tokenHeader;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Autowired
    private JwtTokenUtils jwtTokenUtils;

    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 作用是在每次请求时验证前端传递的 JWT 令牌，并将认证信息存入 Spring Security 上下文。
     * 整体逻辑可以拆解为 “提取令牌→验证令牌→设置认证信息” 三个步骤
     * 在请求到达接口之前，检查请求头中是否有有效的 JWT 令牌，如果有，就 “自动登录” 该用户（让 Spring Security 知道 “当前是谁在访问”）。
     * @author SongHL
     * @date 2025/9/14 13:11
     * @param request
     * @param response
     * @param filterChain
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 1. 从请求头中获取令牌相关的信息
        // tokenHeader 是配置的请求头名称（比如 Authorization），前端会把令牌放在这个请求头里。
        String header = request.getHeader(tokenHeader);

        // 2. 检查请求头是否包含有效的令牌格式
        // 这句意思是：“如果请求头不为空，且以 Bearer 开头，说明可能包含有效的 JWT 令牌”。
        if(header != null && header.startsWith(tokenHead)){
            //3. 提取纯令牌字符串（去掉前缀）
            String authToken = header.substring(tokenHead.length());
            // 4. 从令牌中解析出用户名
            String username = jwtTokenUtils.getUsernameFromToken(authToken);

            // 5. 判断：令牌中有用户名，且当前用户尚未认证（未登录）
            if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){
                // 6. 根据用户名从数据库加载用户信息
                // 通过 userDetailsService 从数据库查询该用户名对应的完整用户信息（包括密码、权限等）。
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);

                // 7. 验证令牌是否有效（比如是否过期、是否被篡改）
                if(jwtTokenUtils.validateToken(tokenHead,userDetails)){

                    // 8. 创建认证对象，并设置到安全上下文（完成“自动登录”）
                    // UsernamePasswordAuthenticationToken 是 Spring Security 表示 “已认证用户” 的对象，包含用户信息和权限。
                    // setAuthentication(authenticationToken) 是核心：将用户信息存入安全上下文，相当于 “告诉 Spring Security，这个用户已经登录了”。
                    //  参数：
                    //“这个用户（userDetails）已经通过认证”；
                    //“不需要再保留密码（null）”；
                    //“这个用户拥有这些权限（getAuthorities()）”。
                    UsernamePasswordAuthenticationToken authenticationToken =
                            new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
            }
        }
        // 9. 放行请求，让请求继续走向后续的过滤器或接口
        // 无论是否认证成功，都要调用这句，否则请求会被拦截在这个过滤器中，无法到达接口。
        filterChain.doFilter(request,response);
    }
}
